home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
301-325
/
disk_313
/
uucp
/
uucp1.lzh
/
src
/
uucico
/
gio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-01-10
|
16KB
|
817 lines
/*
* GIO.C WINDOWED G PROTOCOL
*
* Rewritten from scratch, except the checksum routine which was
* rewritten but based on the old one.
*
* WINDOW SIZE: When changing the window size be sure there
* are enough buffers available for pending txs.
*
* GIO.C (c)Copyright 1989, Matthew Dillon, All Rights Reserved
*/
#include <stdio.h>
#include <stdlib.h>
#include <exec/types.h>
#include <proto/all.h>
void FrameToPacket();
extern int debug;
extern int WindowOne;
#define SUCCESS 0
#define FAIL 1
#define MAGIC 0125252
#define DLE 0x10
#define WINDOWSIZE 2 /* WindowSize = 1 or 2 */
#define SEGSIZEK 2 /* 64 bytes ?? */
#define SUB1(var) (((var)-1)&7)
typedef unsigned char ubyte;
typedef unsigned short uword;
typedef struct {
ubyte Dle; /* Literal ASCII DLE */
ubyte K; /* data size 2^(K+4) except K=0 means no data */
ubyte CL,CH; /* MAGIC - chksum(data) ^ C */
ubyte C;
ubyte X; /* K ^ C0 ^ C1 ^ C */
} Frame;
typedef struct {
ubyte CType; /* bits 7-6 of C */
ubyte CCmd; /* bits 5-3 of C */
ubyte CSeq; /* bits 2-0 of C */
ubyte PLen; /* pre-data (2 bytes) for SHORTDATA type */
ubyte *Data; /* implies CType=LONGDATA or SHORTDATA */
uword DLen; /* length of data */
} Packet;
#define CT_CONTROL (0 << 6)
#define CT_ALTCHN (1 << 6)
#define CT_LONGDATA (2 << 6)
#define CT_SHORTDATA (3 << 6)
#define CT_MASK (3 << 6)
#define CC_CLOSE (1 << 3)
#define CC_RJ (2 << 3)
#define CC_SRJ (3 << 3)
#define CC_RR (4 << 3)
#define CC_INITC (5 << 3)
#define CC_INITB (6 << 3)
#define CC_INITA (7 << 3)
#define CC_MASK (7 << 3)
#define SEQ_MASK 7
#define WAIT_ACK 1
#define WAIT_DATA 2
#define WAIT_CONTROL 3
#define MaxPktSize 4096
char RxBuf[MaxPktSize+4];
char TxBuf[4][MaxPktSize+4];
/* TRANSMIT STAGE */
char TxSeq = 0; /* Last send packet */
char TxPend= 0; /* hasn't been acked yet */
uword TxWinSize; /* 1 or 2 */
uword TxSegSize; /* maximum segment size */
char TxSegK; /* K for TxSegSize */
Packet TxPacket[8]; /* contents of last packet */
/* RECEIVE STAGE */
char RxSeq = 1; /* Next expected recv pkt */
char RxRdy = 0; /* Has come in.. */
char RxRetry = 4;
char RxNotAcked = 0; /* We have yet to ack it */
Packet RxPacket; /* The packet that has come in */
/*
* Get Transmit Buffer. Note that some space to the left is available
*/
char *
GetTxBuf()
{
static int index = 0;
index = (index + 1) & 3;
return(TxBuf[index] + 2);
}
int
gwrdata(fi)
FILE *fi;
{
int bytes;
char *buf = GetTxBuf();
if (debug > 7)
printf("GWRDATA: ");
while ((bytes = fread(buf, 1, TxSegSize, fi)) >= 0) {
if (SendDataPacket(buf, bytes) != SUCCESS) {
if (debug > 7)
printf("GWR Failed\n");
return(FAIL);
}
if (debug > 7)
printf("\nGWROK ");
if (bytes == 0)
break;
buf = GetTxBuf();
}
if (debug > 7)
printf("\nGWFile Last Ack\n");
while (TxPend) {
if (GetData(WAIT_ACK, NULL) == FAIL)
return(FAIL);
}
return (SUCCESS);
}
/*
* Write message to the other guy.
*
* NOTE: LONGDATA packets used exclusively and \0 fill to end.
*/
int
gwrmsg(str)
char *str;
{
int len = strlen(str) + 1; /* type + str + \0 */
if (debug > 8)
printf("GWRMSG: %s\n", str);
while (len > TxSegSize) {
char *buf = GetTxBuf();
movmem(str, buf, TxSegSize);
if (debug > 8)
printf("GWR-SEND %d\n", TxSegSize);
if (SendDataPacket(buf, TxSegSize) != SUCCESS)
return(FAIL);
len -= TxSegSize;
str += TxSegSize;
}
/*
* Find optimal packet size (remember, we must force LONGDATA
*
* Apparently packet sizes less than the agreed upon size are
* not allowed ???
*/
{
short siz = TxSegSize;
char *buf = GetTxBuf();
#ifdef NOTDEF
short k = TxSegK;
while (k > 1 && (siz >> 1) >= len) {
--k;
siz >>= 1;
}
#endif
if (debug > 8)
printf("GWR-FNL %d %d\n", len, siz);
movmem(str, buf, len);
setmem(buf + len, siz - len, 0);
if (SendDataPacket(buf, siz) != SUCCESS) {
if (debug > 8)
printf("GWR-FAIL\n");
return(FAIL);
}
}
if (debug > 8)
printf("GWR Last Ack\n");
while (TxPend) {
if (GetData(WAIT_ACK, NULL) == FAIL)
return(FAIL);
}
return (SUCCESS);
}
int
grddata(fi)
FILE *fi;
{
int bytes;
char *buf;
if (debug > 7)
printf("GRDDATA\n");
while ((bytes = RecvDataPacket(&buf)) > 0) {
if (debug > 7)
printf("GRDDATA blk %d\n", bytes);
fwrite(buf, 1, bytes, fi);
}
if (debug > 7)
printf("GRDDATA end %d\n", bytes);
if (bytes < 0)
return(FAIL);
else
return(SUCCESS);
}
grdmsg(buf, maxlen)
char *buf;
{
short i;
short n;
short slen;
char *ptr;
i = 0;
if (debug > 8)
printf("GRDMSG\n");
while ((n = RecvDataPacket(&ptr)) > 0) {
ptr[n] = 0;
slen = strlen(ptr);
if (slen > maxlen - 1) {
printf("GRDMSG: Buffer overflow!\n");
return (FAIL);
}
movmem(ptr, buf + i, slen);
buf[i + slen] = 0;
if (slen != n)
break;
i += slen;
maxlen -= slen;
}
if (debug > 8)
printf("GRDMSGEND %d (%d) %s\n", n, i, buf);
if (n < 0) {
buf[0] = 0;
return(FAIL);
}
return(SUCCESS);
}
SendDataPacket(buf, bytes)
ubyte *buf;
int bytes;
{
Packet P;
/*
* If window exhausted we must wait for at least one ack.
*/
if (TxPend == TxWinSize) {
if (GetData(WAIT_ACK, NULL) == FAIL)
return(FAIL);
}
TxSeq = (TxSeq + 1) & 7; /* next Tx packet */
/*
* Figure out best fit packet size. Apparently packets smaller
* then the agreed upon size are not allowed ???
*/
#ifdef NOTDEF
{
short k = TxSegK;
P.DLen = TxSegSize;
while (k > 1 && P.DLen && (P.DLen >> 1) >= bytes) {
--k;
P.DLen >>= 1;
}
}
#else
P.DLen = TxSegSize;
#endif
if (bytes < P.DLen) {
uword extra = P.DLen - bytes;
setmem(buf + bytes, extra, 0);
if (extra <= 127) {
P.PLen = 1;
buf[-1] = extra;
} else {
P.PLen = 2;
buf[-2] = 0x80 | extra;
buf[-1] = (extra >> 7);
}
P.CType = CT_SHORTDATA;
} else {
P.PLen = 0;
P.CType = CT_LONGDATA;
}
P.CCmd = TxSeq << 3; /* transmit sequence number */
P.CSeq = (RxSeq - 1) & 7; /* last valid received pkt */
P.Data = buf;
if (debug > 8)
printf("WRITE PACKET %d %d\n", TxSeq, P.CSeq);
if (RxNotAcked) /* We've acked the rx packet */
RxNotAcked = 0;
TxPacket[TxSeq & 7] = P;
++TxPend;
WritePacket(&TxPacket[TxSeq & 7], 1);
return(SUCCESS);
}
RecvDataPacket(pbuf)
char **pbuf;
{
if (RxRdy == 0) {
if (GetData(WAIT_DATA, NULL) != SUCCESS)
return(-1);
}
*pbuf = RxPacket.Data;
RxRdy = 0;
return((int)RxPacket.DLen);
}
gturnon(master)
{
Packet P;
short retry = 5;
short windowsize = WINDOWSIZE; /* our prefered window size */
short segsize = SEGSIZEK; /* our prefered segment size */
if (WindowOne)
windowsize = 1;
if (master) {
while (retry > 0) {
WriteCtlPacket(CC_INITA | windowsize);
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITA) {
if (P.CSeq && P.CSeq < windowsize)
windowsize = P.CSeq;
break;
}
--retry;
}
while (retry > 0) {
WriteCtlPacket(CC_INITB | (segsize - 1));
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITB) {
if (P.CSeq < segsize - 1)
segsize = P.CSeq + 1;
break;
}
--retry;
}
while (retry > 0) {
WriteCtlPacket(CC_INITC | windowsize);
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITC) {
if (P.CSeq && P.CSeq < windowsize)
windowsize = P.CSeq;
break;
}
--retry;
}
} else {
while (retry > 0) {
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITA) {
WriteCtlPacket(CC_INITA | windowsize);
if (P.CSeq && windowsize > P.CSeq)
windowsize = P.CSeq;
break;
}
--retry;
}
while (retry > 0) {
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITB) {
WriteCtlPacket(CC_INITB | (segsize - 1));
if (P.CSeq < segsize - 1)
segsize = P.CSeq + 1;
break;
}
--retry;
}
while (retry > 0) {
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITC) {
WriteCtlPacket(CC_INITC | windowsize);
if (P.CSeq && windowsize > P.CSeq)
windowsize = P.CSeq;
break;
}
--retry;
}
}
TxSegK = segsize;
TxSegSize = 1 << (TxSegK + 4);
TxWinSize = windowsize;
if (debug > 0)
printf("Window Size is %d\n", TxWinSize);
if (retry == 0)
return(FAIL);
return(SUCCESS);
}
gturnoff()
{
Packet P;
WriteCtlPacket(CC_CLOSE);
if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_CLOSE) {
WriteCtlPacket(CC_RR | ((RxSeq - 1) & 7));
return (SUCCESS);
}
return (FAIL);
}
GetData(waitfor, p)
Packet *p;
{
Packet P;
short timeout;
/*
* If we haven't acked the last packet we received we must do
* so now before we can expect to receive another one!
*/
if (waitfor == WAIT_ACK)
timeout = 20;
else if (waitfor == WAIT_DATA)
timeout = 40;
else
timeout = 40;
for (;;) {
if (RxNotAcked) {
WriteCtlPacket(CC_RR | SUB1(RxSeq));
RxNotAcked = 0;
}
if (ReadPacket(&P, timeout) == FAIL) {
if (waitfor == WAIT_DATA) {
if (RxRetry) {
--RxRetry;
if (debug > 8)
printf("\nWAIT-DATA, TIMEOUT, SEND RJ\n");
WriteCtlPacket(CC_RJ | SUB1(RxSeq));
continue;
}
}
if (waitfor == WAIT_ACK) {
if (RxRetry) {
--RxRetry;
if (debug > 8)
printf("\nWAIT-ACK, TIMEOUT, RETRY\n");
WritePacket(&TxPacket[(TxSeq - TxPend + 1) & 7], 1);
continue;
}
}
if (debug > 8)
printf("COMPLETE FAILURE RxRetry = %d\n", RxRetry);
return(FAIL);
}
RxRetry = 4;
switch(P.CType) {
case CT_CONTROL:
switch(P.CCmd) {
case CC_CLOSE: /* End of communication ... not an ACK! */
if (waitfor == WAIT_CONTROL) {
*p = P;
return(SUCCESS);
}
return(FAIL);
case CC_RJ: /* Reject packet (P.CSeq == last good packet) */
/* resend last packet */
WritePacket(&TxPacket[(P.CSeq + 1) & 7], 1);
{
short i;
for (i = 0; i < TxPend; ++i) {
if (P.CSeq == ((TxSeq - i) & 7))
break;
}
if (i == TxPend)
printf("RJ, bad seq no: %d expected %d-%d\n", P.CSeq, (TxSeq - TxPend + 1) & 7, TxSeq);
}
break;
case CC_SRJ: /* Selective Reject (P.CSeq == bad packet # ) */
return(FAIL);
case CC_RR: /* Ack to packet (P.CSeq == packet # acked) */
if (RecvdAck(P.CSeq) == SUCCESS && waitfor == WAIT_ACK)
return(SUCCESS);
break;
case CC_INITC:
case CC_INITB:
case CC_INITA:
if (waitfor == WAIT_CONTROL) {
*p = P;
return(SUCCESS);
}
return(FAIL);
}
break;
case CT_ALTCHN:
printf("ALTCHN packet ??\n");
break;
case CT_LONGDATA:
case CT_SHORTDATA:
{
char rxseq = P.CCmd >> 3;
char txack = P.CSeq;
if (RxRdy == 1) {
printf("Got two receive packets without me acking!\n");
}
if (rxseq == SUB1(RxSeq)) {
RxNotAcked = 1;
continue; /* ignore resent pkts we already have */
} else if (rxseq != RxSeq) {
if (rxseq == ((RxSeq + 1) & 7)) /* missed one (windowed) */
WriteCtlPacket(CC_RJ | SUB1(RxSeq));
printf("Received sequence %d, expected %d\n", rxseq, RxSeq);
break;
} else {
if (debug > 6)
printf("RECV SEQUENCE %d\n", rxseq);
}
RecvdAck(txack);
/*
* Delay sending the ACK back in case we can combine
* it with the next transmitted packet.
*/
RxNotAcked = 1; /* we haven't ack'd the rx packet */
RxSeq = (RxSeq + 1) & 7;
RxRdy = 1;
RxPacket = P;
if (waitfor == WAIT_DATA)
return(SUCCESS);
if (TxPend == 0 && waitfor == WAIT_ACK)
return(SUCCESS);
}
break;
}
}
}
RecvdAck(seq)
char seq;
{
short i;
short seqbase = TxSeq - TxPend + 1;
/*
* which packet was acked?
*/
for (i = 0; i < TxPend; ++i) {
if (seq == ((seqbase + i) & 7))
break;
}
if (i == TxPend) {
if (TxPend)
printf("He acked the wrong packet! %d expected %d\n", seq, TxSeq);
return(FAIL);
}
if (debug > 8)
printf("TxPend %d ->", TxPend);
TxPend = TxPend - i - 1;
if (debug > 8)
printf(" %d\n", TxPend);
return(SUCCESS);
}
WriteCtlPacket(cc)
{
Packet pk;
pk.CType = CT_CONTROL;
pk.CCmd = cc & CC_MASK;
pk.CSeq = cc & SEQ_MASK;
pk.PLen = 0;
pk.DLen = 0;
WritePacket(&pk, 0);
return(SUCCESS);
}
WritePacket(pk, async)
Packet *pk;
{
Frame F;
uword sum;
F.Dle = DLE;
F.C = pk->CType | pk->CCmd | pk->CSeq;
F.K = 9;
if (pk->CType == CT_SHORTDATA || pk->CType == CT_LONGDATA)
F.K = LenToK(pk->DLen);
else
pk->DLen = 0;
sum = MAGIC - (CheckSum(pk->Data - pk->PLen, pk->DLen) ^ F.C);
F.CH = sum >> 8;
F.CL = sum;
F.X = F.K ^ F.CH ^ F.CL ^ F.C;
if (debug > 8)
printf("WritePacket: F.K = %d F.C = %02x\n", F.K, F.C);
if (async)
xwritea(&F, sizeof(F));
else
xwrite(&F, sizeof(F)); /* write header */
if (pk->DLen) { /* write data */
if (async)
xwritea(pk->Data - pk->PLen, pk->DLen);
else
xwrite(pk->Data - pk->PLen, pk->DLen);
}
return(SUCCESS);
}
ReadPacket(pk, timeout)
Packet *pk;
{
Frame F;
short c;
short i = 0;
pk->Data = RxBuf;
pk->CType = 0xFF;
pk->CCmd = 0;
pk->CSeq = 0;
if (debug > 8)
printf("ReadPacket\n");
while ((c = xgetc(timeout)) != EOF) {
if (debug > 8)
printf("RP %d %02x\n", i, c);
switch(i) {
case 0:
if (c == DLE) {
F.Dle = c;
++i;
}
break;
case 1:
F.K = c;
++i;
if (c == DLE) { /* K only valid 0-9 */
F.Dle = c;
i = 1;
}
break;
case 2:
F.CL = c;
++i;
break;
case 3:
F.CH = c;
++i;
break;
case 4:
F.C = c;
++i;
break;
case 5:
F.X = c;
if (F.X != (F.K ^ F.CH ^ F.CL ^ F.C)) {
printf("F.X failed: %02x %02x\n", F.X, (F.K ^ F.CH ^ F.CL ^ F.C));
i = 0;
} else { /* get data segment if any */
++i;
}
break;
}
if (i == 6)
break;
}
if (debug > 8)
printf("RP Hdr i = %d, F.K = %d F.C = %02x\n", i, F.K, F.C);
if (i == 6) { /* Receive Data Portion */
uword pktsize = 1 << (F.K + 4);
uword n;
if (F.K == 0 || F.K == 9)
pktsize = 0; /* FIXME is K=0 an illegal case? */
if (pktsize > MaxPktSize) {
printf("Protocol failure pktsize %d/%d/%d\n", pktsize, TxSegSize, MaxPktSize);
return (FAIL);
}
for (n = 0; n < pktsize; ++n) {
if ((c = xgetc(4)) == EOF)
break;
pk->Data[n] = c;
}
if (c != EOF) {
uword hissum;
uword oursum;
hissum = (F.CH << 8) | F.CL;
oursum = MAGIC - (CheckSum(pk->Data, pktsize) ^ F.C);
if (debug > 8)
printf("Got Data, checking: %04x %04x\n", hissum, oursum);
if (hissum == oursum) {
FrameToPacket(&F, pk, pk->Data);
return (SUCCESS);
}
} else {
FrameToPacket(&F, pk, pk->Data); /* mainly for pk->CType */
return (FAIL);
}
}
/*
* Timeout, retry?
*/
return (FAIL);
}
CheckSum(s, n)
ubyte *s;
int n;
{
uword sum;
uword x;
uword t;
if (n == 0)
return(0);
sum = -1;
x = 0;
while (n) {
if (sum & 0x8000)
sum = (sum << 1) | 1;
else
sum = (sum << 1);
t = sum;
sum += *s++;
x += sum ^ n;
if (sum <= t)
sum ^= x;
--n;
}
return((int)sum);
}
void
FrameToPacket(fr, pk, data)
Frame *fr;
Packet *pk;
ubyte *data;
{
pk->CType = fr->C & CT_MASK;
pk->CCmd = fr->C & CC_MASK;
pk->CSeq = fr->C & SEQ_MASK;
switch(pk->CType) {
case CT_LONGDATA:
pk->DLen = 1 << (fr->K + 4);
break;
case CT_SHORTDATA:
pk->DLen = 1 << (fr->K + 4);
if (pk->Data[0] & 0x80) {
pk->DLen -= (pk->Data[0] & 0x7F) | (pk->Data[1] << 7);
if (pk->DLen < 0) {
printf("DLEN ERROR %d\n", pk->DLen);
pk->DLen = 0;
}
pk->Data += 2;
} else {
pk->DLen -= *pk->Data;
++pk->Data;
}
break;
default:
pk->DLen = 0;
break;
}
}
LenToK(bytes)
uword bytes;
{
uword n = 32;
uword k = 1;
while (n < bytes) {
n <<= 1;
++k;
}
if (k > 8) {
printf("Soft error, LenToK: %d %d %d\n", bytes, n, k);
k = 8;
}
return((int)k);
}